AddCSLuaFile( "cl_init.lua" )
AddCSLuaFile( "shared.lua" )
include('shared.lua')

function ENT:Initialize()
	self.Entity:SetModel("models/props_lab/reciever01b.mdl")
	self.Entity:PhysicsInit( SOLID_VPHYSICS )
	self.Entity:SetMoveType(MOVETYPE_VPHYSICS)
	self.Entity:SetSolid(SOLID_VPHYSICS)
	self.Entity:SetUseType(SIMPLE_USE)
	
	self.code = 0
	self.autoclose = false
	self.didclose = false	--Without this, the iris would close within a half second of opening.
	self.donotautoopen = false	--Open automatically when a correct code comes in?
	self.CodeStatus = 0
	self.closetime = 0
	self.wireCode = 0
	self.IrisStatus = 0
	self.LockedGate = self.Entity
	self.LockedIris = self.Entity
	self.CodesInString = "";
	self.Codes = {};
	self.wireDesc = "";
	self.buster = self.Entity
	self.busterfire = 0
	self.owners = self:FindOwner()
	
	self.Inputs = WireLib.CreateInputs(self.Entity, { "Iris Control" })
	self.Outputs = WireLib.CreateOutputs( self.Entity, { "Incoming Wormhole", "Code Status", "Gate Active", "Received Code", "Code Description [STRING]", "Iris Status", "Iris Buster Access" })	

end

local function AutoClose(EntTable)	--timer function
	local gate, iris
	if EntTable.LockedGate == EntTable.Entity then
		gate, iris = EntTabble:FindGate()
	else
		gate, iris = EntTable.LockedGate, EntTable.LockedIris
	end
	if gate.IsOpen and not iris.IsActivated then
		iris:Toggle()
		EntTable.didclose = true
	end
	EntTable.wireCode = 0
	EntTable.CodeStatus = 0
end

function ENT:SpawnFunction( ply, tr )
	if ( !tr.Hit ) then return end
	
	local ang = ply:GetAimVector():Angle(); ang.p = 0; ang.r = 0; ang.y = (ang.y+180) % 360;
	
	local ent = ents.Create("iris_computer_sf");
	ent:SetAngles(ang);
	ent:SetPos(tr.HitPos+Vector(0,0,20));
	ent:Spawn();
	ent:Activate();
	
	local phys = ent:GetPhysicsObject()
	if ValidEntity(phys) then phys:EnableMotion(false) end

	return ent	
end

function ENT:Use(ply)
	umsg.Start("gdopc_openpanel", ply)
	umsg.String(self.closetime .. ";" .. tostring(self.autoclose) .. ";" .. tostring(self.donotautoopen) .. ";" .. self.CodesInString)
	umsg.End()
	ply.IrisCompEnt=self
end

function ENT:Touch(ent)
	if self.LockedGate == self.Entity then
		if (string.find(ent:GetClass(), "stargate") or string.find(ent:GetClass(), "iris")) then
			local gate, iris = self:FindGate()
			if iris ~= nil and gate ~= nil and gate:IsValid() and iris:IsValid() and iris:GetOwner() == self:GetOwner() then
				self.LockedGate = gate
				self.LockedIris = iris
				local ed = EffectData()
 					ed:SetEntity( self.Entity )
 				util.Effect( "propspawn", ed, true, true )
			end
		end
	end
end

function ENT:Think()

	local gate, iris
	if self.LockedGate == self.Entity then
		gate, iris = self:FindGate()
	else
		gate = self.LockedGate
		iris = self.LockedIris
	end
	if gate and iris then 
		if not iris.IsActivated then
			self.IrisStatus=0
		else
			self.IrisStatus=1
		end
		if iris:GetOwner() == self:GetOwner() then
			if not gate.Outbound and (gate.IsOpen or gate.Dialling) then
				if self.autoclose and not self.didclose then
					if not iris.IsActivated then
						iris:Toggle()
						self.didclose = true	--We won't close the iris again until then next time the gate is active
					end
				end
				if gate.IsOpen and self:FindBuster() then
					self.buster = self:FindBuster()
					local tgate = gate.Target
					local tgatea = tgate:GetGateAddress()
					local tgaten = tgate:GetGateName()
					local gatea = gate:GetGateAddress()
					local gaten = gate:GetGateName()
					if self.buster.CanFire and iris.IsActivated and (self.busterfire == 0) then
						self.owners:ChatPrint("Iris is being Breached")
						self.owners:ChatPrint(" - at (name: " .. gaten .. " , add: " .. tostring(gatea) .. " )")
						self.owners:ChatPrint(" - from (name: " .. tgaten .. " , add: " .. tostring(tgatea) .. " )")
						self.busterfire = 1
					elseif (self.CodeStatus == 0) and self.busterfire ==1 and (not iris.IsActivated) then
						self.owners:ChatPrint("Iris Breached at (name: " .. gaten .. " , add: " .. tostring(gatea) .. " )")
						self.busterfire = 0
					elseif self.CodeStatus ==1 then
						self.busterfire = 0
					end
				else
					self.busterfire = 0
				end
				for v,k in pairs(self.Codes) do
					if self.wireCode == tonumber(v) then
					self.wireDesc=k
					end
				end
			else
				self.wireCode = 0
				self.CodeStatus = 0
				self.busterfire = 0
				self.wireDesc=""
			end
		end
			
		if not (gate.IsOpen or gate.Dialling) and self.didclose and iris.IsActivated then
			self.didclose = false	--Resetting so we can autoclose again
			iris:Toggle()		--Make this optional in the future?
		end
		
		if self.didclose and not (gate.IsOpen or gate.Dialling) then
			self.didclose = false
		end
		

		if gate.IsOpen or gate.Dialling then
			Wire_TriggerOutput(self.Entity, "Gate Active", 1)
			if not gate.Outbound then
				Wire_TriggerOutput(self.Entity, "Incoming Wormhole", 1)
			else
				Wire_TriggerOutput(self.Entity, "Incoming Wormhole", 0)
			end
		else
			Wire_TriggerOutput(self.Entity, "Gate Active", 0)
		end
		
			
		if self.donotautoopen and not gate.IsOpen then
			self.CodeStatus = 0
		end

	end
	if gate and not iris then 
		self.IrisStatus = -1
	end
	Wire_TriggerOutput(self.Entity, "Code Status", self.CodeStatus)
	Wire_TriggerOutput(self.Entity, "Received Code", self.wireCode)
	Wire_TriggerOutput(self.Entity, "Code Description", self.wireDesc)
	Wire_TriggerOutput(self.Entity, "Iris Buster Access", self.busterfire)
	Wire_TriggerOutput(self.Entity, "Iris Status", self.IrisStatus)

	self.Entity:NextThink(CurTime()+0.5)
	return true
end

function ENT:TriggerInput(iname, value)
	local gate, iris, aopen, aclose
	if self.LockedGate == self.Entity then
		gate, iris = self:FindGate()
	else
		gate = self.LockedGate
		iris = self.LockedIris
	end
	if iname == "Iris Control" then
		iris:Toggle()
		if value == 0 and self.closetime ~= 0 then
			timer.Simple(self.closetime, AutoClose, self)
		end
	end
end

---------------------------------------------
-- Server/Client crossover stuff
---------------------------------------------

function ReceiveCodes(player, command, args)
	if player.IrisCompEnt and player.IrisCompEnt ~= NULL then
		local codes = {};
		if (args[4] != "" and args[4] != " ") then
			local tempvar = ""
			for k,v in pairs(string.Explode("|", args[4])) do
				tempvar = string.Explode(",", v)
				codes[tempvar[2]] = tempvar[1]
			end
		end
		player.IrisCompEnt.CodesInString = args[4];
		player.IrisCompEnt.Codes = codes;
		
		player.IrisCompEnt.closetime = tonumber(args[1])
		player.IrisCompEnt.autoclose = util.tobool(args[2])
		player.IrisCompEnt.donotautoopen = util.tobool(args[3])	
		
		player.IrisCompEnt = nil;
	end
end
concommand.Add("setcodes", ReceiveCodes)

function ToggleIris(player, command, args)
	if player.IrisCompEnt and player.IrisCompEnt ~= NULL then
		if player.IrisCompEnt.LockedGate == player.IrisCompEnt.Entity then
			_, iris = player.IrisCompEnt:FindGate()
		else
			 iris = player.IrisCompEnt.LockedIris
		end
		if ValidEntity(iris) then iris:Toggle() end
	end
end
concommand.Add("togiris", ToggleIris)

---------------------------------------------
-- Gate Stuff
---------------------------------------------

function ENT:FindGate()  -- from aVoN's DHD
	local gate
	local iris
	local dist = 1000
	local pos = self.Entity:GetPos()
	for _,v in pairs(ents.FindByClass("stargate_*")) do
		if(v.IsStargate) then
			local sg_dist = (pos - v:GetPos()):Length()
			if(dist >= sg_dist) then
				dist = sg_dist
				gate = v
			end
		end
	end
	dist = 1000
	for _,v in pairs(ents.FindByClass("*_iris")) do
		if(v.IsIris) then
			local i_dist = (pos - v:GetPos()):Length()
			if(dist >= i_dist) then
				dist = i_dist
				iris = v
			end
		end
	end
	return gate, iris
end

function ENT:RecieveIrisCode(code)
	local gate, iris
	if self.LockedGate == self.Entity then
		gate, iris = self:FindGate()
	else
		gate = self.LockedGate
		iris = self.LockedIris
	end
	local ret = 0
	self.wireCode = code
		for v,_ in pairs(self.Codes) do
			if code == tonumber(v) then
				if iris.IsActivated then
					if not self.donotautoopen then
						iris:Toggle()
						ret = 1
						self.CodeStatus = 1
						if self.closetime ~= 0 then
							timer.Simple(self.closetime, AutoClose, self)
						end
					else
						ret = 2
						self.CodeStatus = 1
					end
					self.wireDesc = "";
				end
			end
		end
		if self.CodeStatus == 0 and self.donotautoopen then	-- if no code was found, this'll be 0 still
			self.CodeStatus = 2			-- so, that means the code was wrong
		end

	return ret
end

function ENT:FindBuster()
	local gate, tgate, iris, buster
	gate, iris = self:FindGate()
	local dist = 300
	if (ValidEntity(gate))then
		if gate.IsOpen then
		tgate = gate.Target
			if (ValidEntity(tgate))then
				local pos = tgate:GetPos()
				for _,v in pairs(ents.FindByClass("iris_buster")) do
					local sg_dist = (pos - v:GetPos()):Length()
					if(dist >= sg_dist) then
						dist = sg_dist
						buster = v
					end
				end
			end
		end
	end
	return buster
end

function ENT:FindOwner()
	local owners
	local dist = 1000
	local pos = self.Entity:GetPos()
	for _,v in pairs(ents.FindByClass("playe*")) do
		local sg_dist = (pos - v:GetPos()):Length()
		if(dist >= sg_dist) then
			dist = sg_dist
			owners = v
		end
	end
	return owners
end